#include "AVPictureX.h"

namespace FFMPEGCPP
{

CAVPicture::CAVPicture()
{
	memset( &m_AVPicture,0,sizeof(m_AVPicture) );
	m_AVPixelFormat = AV_PIX_FMT_NONE;
	m_nHeight = 0;
	m_nWidth = 0;
	m_bAlloced = false;
	m_bValid =false;
	m_PTS =  AV_NOPTS_VALUE;
	m_TimeBase.den = -1;
	m_TimeBase.num = 0;
}

CAVPicture::~CAVPicture()
{
	Free();
}

bool CAVPicture::Alloc( enum AVPixelFormat pix_fmt, int width, int height )
{
	if( true == m_bAlloced )
	{
		if( m_AVPixelFormat == pix_fmt 
			&& m_nHeight == height
			&& m_nWidth == width )return true;
	}

	
	Free();
	

	m_bValid = (0 == avpicture_alloc( &m_AVPicture,pix_fmt,width,height ));

	if(m_bValid)
	{
		m_AVPixelFormat = pix_fmt;
		m_nHeight = height;
		m_nWidth = width;
		m_bAlloced = true;
	}
	
	return m_bValid;
}

void CAVPicture::Free()
{
	if(m_bAlloced)avpicture_free( &m_AVPicture );

	m_AVPixelFormat = AV_PIX_FMT_NONE;
	m_nHeight = 0;
	m_nWidth = 0;
	m_bAlloced = false;
	m_bValid =false;
}

void CAVPicture::FromAVFrame( const AVFrame* frame,AVRational timebase )
{
	Free();

	m_TimeBase = timebase;
	m_AVPixelFormat = (enum AVPixelFormat)frame->format;
	m_nHeight = frame->height;
	m_nWidth = frame->width;
	for( int i = 0;i<AV_NUM_DATA_POINTERS;++i)
	{
		m_AVPicture.data[i] = frame->data[i];
		m_AVPicture.linesize[i] = frame->linesize[i];
	}
	m_PTS = frame->pts;
	if( AV_NOPTS_VALUE == m_PTS )
	{
		m_PTS = av_frame_get_best_effort_timestamp(frame);
	}
	if( AV_NOPTS_VALUE == m_PTS )
	{
		m_PTS = frame->pkt_pts;
	}
	if( AV_NOPTS_VALUE == m_PTS )
	{
		m_PTS = frame->pkt_dts;
	}

	m_bValid = true;
}

int CAVPicture::GetSize() const
{
	return avpicture_get_size( m_AVPixelFormat,m_nWidth,m_nHeight );
}

bool CAVPicture::Layout( void* poutbuffer,int outbuffersize )
{
	if( false== m_bValid )return false;
	return 0 < avpicture_layout( &m_AVPicture,m_AVPixelFormat,m_nWidth,m_nHeight,(unsigned char*)poutbuffer,outbuffersize );
}

bool CAVPicture::Fill( const void* pinbuffer,int inbuffersize )
{
	if( false== m_bValid )return false;
	if( inbuffersize < GetSize() )return false;
	return 0 == avpicture_fill( &m_AVPicture,(const uint8_t *)pinbuffer,m_AVPixelFormat,m_nWidth,m_nHeight );
}

const AVPicture* CAVPicture::GetPicture() const
{	
	return &m_AVPicture;
}

int CAVPicture::GetWidth() const
{
	return m_nWidth;
}

int CAVPicture::GetHeight() const
{
	return m_nHeight;
}

enum AVPixelFormat CAVPicture::GetFormat() const
{
	return m_AVPixelFormat;
}

int64_t CAVPicture::GetPTS() const
{
	return m_PTS;
}

void CAVPicture::SetPTS( int64_t t )
{
	m_PTS = t;
}

AVRational CAVPicture::GetTimer()
{
	AVRational t;

	t = m_TimeBase;
	t.num *= m_PTS;
	return t;
}

void CAVPicture::SetTimeBase( AVRational t )
{
	m_TimeBase = t;
}

AVRational CAVPicture::GetTimeBase() const
{	
	return m_TimeBase;
}


CPicturePool::CPicturePool()
{
	m_nMaxFreeCount = 3;
}
CPicturePool::~CPicturePool()
{
	Clear();
}
void CPicturePool::Setmaxfreecount( int nCount /*= 3 */ )
{
	m_nMaxFreeCount = nCount;
}

CPictureItem* CPicturePool::Alloc( enum AVPixelFormat pix_fmt, int width, int height )
{
	CPictureItem* p = 0;
	XLIB2::CXQueItem*	item;

	if( XLIB2::TXQue<XLIB2::CXQueItem>::size() > 0 )
	{
		item = XLIB2::TXQue<XLIB2::CXQueItem>::pop_front();
		if( item )p = (CPictureItem*)item->data();
	}

	if(0  == p )
	{
		p = new CPictureItem();
		p->poolitem.set_data( p );
	}

	p->Alloc( pix_fmt,width,height );

	
	return p;
}

void CPicturePool::Free( CPictureItem* pItem )
{
	if( XLIB2::TXQue<XLIB2::CXQueItem>::size() > m_nMaxFreeCount )
	{
		pItem->Free();
		delete pItem;
	}else
	{
		XLIB2::TXQue<XLIB2::CXQueItem>::push_back( &pItem->poolitem );
	}
}

void CPicturePool::on_clear_item( XLIB2::CXQueItem* item )
{
	CPictureItem* p = 0;

	if( item )p = (CPictureItem*)item->data();

	if(p)
	{
		p->Free();
		delete p;
	}
}

void CPicturePool::Clear()
{
	XLIB2::TXQue<XLIB2::CXQueItem>::clear();
}





void CPictureQue::on_clear_item( XLIB2::CXQueItem* item )
{
	CPictureItem* p = 0;

	if( item )p = (CPictureItem*)item;

	if(p)
	{
		p->Free();
		delete p;
	}
}

}